import datetime

import xcc

from millhouse.exceptions import XMLdbException

def load_session(user, password, host, port, dbname=''):
    return xcc.Session(user, password, host, dbname, port)

def _result(response):
    while response.has_next():
        yield unicode(response.next_item())

def adhoc_query(session, message, buffer=False):
    request = session.new_adhoc_query(message)
    if buffer:
        return _result(request.submit())
    else:
        response = request.submit()
        result = []
        while response.has_next():
            result.append(unicode(response.next_item()).strip())
        return result

def load_module(session, module, filename=None):
    content = session.new_content()
    content.set_file_name(module)
    content.set_uri(filename)
    content.set_repair(xcc.CORRECTION_NONE)
    content.set_format(xcc.FORMAT_NONE)
    #content.add_permission(xcc.READ, 'admin')
    #content.add_permission(xcc.UPDATE, 'admin')
    #content.add_permission(xcc.INSERT, 'admin')
    #content.add_permission(xcc.EXECUTE, 'admin')
    try:
        bytes = content.insert()
    except xcc.XQueryError:
        raise XMLdbException("Unable to load %s" % module)
    if bytes == 0:
        raise XMLdbException("0-byte load for %s, possibly failed insert." % module)

def coerce_vars(**kwargs):
    vartypes = dict(str=xcc.STRING, int=xcc.INTEGER, float=xcc.FLOAT,
                    bool=xcc.BOOLEAN, datetime=xcc.DATETIME)
    results = []
    for key, val in kwargs.iteritems():
        typ = type(val).__name__
        if not isinstance(val, basestring):
            val = str(val)
        results.append((vartypes[typ], key, val))
    return results

def invoke_module(session, module, *args, **kwargs):
    request = session.new_module_invoke(module)
    bind_vars = coerce_vars(**kwargs)
    for xcc_type, name, val in bind_vars:
        request.set_variable(xcc_type, '', name, val)
    
    response = request.submit()
    result = []
    while response.has_next():
        result.append(unicode(response.next_item()).strip())
    return result
